import type { PluginOption } from 'vite';

import type { ArchiverPluginOptions } from '../typing';

import fs from 'node:fs';
import fsp from 'node:fs/promises';
import { join } from 'node:path';

import archiver from 'archiver';

export const viteArchiverPlugin = (options: ArchiverPluginOptions = {}): PluginOption => {
    return {
        apply: 'build',
        closeBundle: {
            handler() {
                const { name = 'dist', outputDir = '.' } = options;

                setTimeout(async () => {
                    const folderToZip = 'dist';

                    const zipOutputDir = join(process.cwd(), outputDir);
                    const zipOutputPath = join(zipOutputDir, `${name}.zip`);
                    try {
                        await fsp.mkdir(zipOutputDir, { recursive: true });
                    } catch {
                        // ignore
                    }

                    try {
                        await zipFolder(folderToZip, zipOutputPath);
                        console.log(`Folder has been zipped to: ${zipOutputPath}`);
                    } catch (error) {
                        console.error('Error zipping folder:', error);
                    }
                }, 0);
            },
            order: 'post',
        },
        enforce: 'post',
        name: 'vite:archiver',
    };
};

async function zipFolder(folderPath: string, outputPath: string): Promise<void> {
    return new Promise((resolve, reject) => {
        const output = fs.createWriteStream(outputPath);
        const archive = archiver('zip', {
            zlib: { level: 9 }, // 设置压缩级别为 9 以实现最高压缩率
        });

        output.on('close', () => {
            console.log(`ZIP file created: ${outputPath} (${archive.pointer()} total bytes)`);
            resolve();
        });

        archive.on('error', (err) => {
            reject(err);
        });

        archive.pipe(output);

        // 使用 directory 方法以流的方式压缩文件夹，减少内存消耗
        archive.directory(folderPath, false);

        // 流式处理完成
        archive.finalize();
    });
}
